{%- assign min = 1 -%}
{%- assign max = 999999 -%}
{%- assign diff = max | minus: min -%}
{%- assign rbrace = "}" -%}
{%- assign lbrace = "{" -%}
{%- assign actuatorEndpointRandomNumber = include.endpoints | remove: "," | truncate: 50, '' -%}
{%- assign endpoints = include.endpoints | split: "," -%}
{% capture troubleshooting %}
```xml
<Logger name="org.pac4j" level="debug" additivity="false">
    <AppenderRef ref="console" />
    <AppenderRef ref="file" />
</Logger>
<Logger name="org.springframework.security" level="debug" additivity="false">
    <AppenderRef ref="console" />
    <AppenderRef ref="file" />
</Logger>
```
{% endcapture %}

{%- capture endpointprops -%}{% include_cached thirdpartyproperties.html
disablePagination="true"
disableSearch="true"
id=actuatorEndpointRandomNumber
disableNotes="true"
thirdPartyStartsWith="management.endpoints,management.health,management.endpoint.health" %}
{%- endcapture -%}

{%- capture basicauthprops -%}{% include_cached thirdpartyproperties.html
disablePagination="true"
disableSearch="true"
disableNotes="true"
id=actuatorEndpointRandomNumber
forcePropertyTabsOnClick="true"
thirdPartyStartsWith="spring.security.user" %}
{%- endcapture -%}

{%- capture jdbcauthprops -%}{% include_cached casproperties.html
disableSearch="true"
id=actuatorEndpointRandomNumber
disablePagination="true"
disableNotes="true"
forcePropertyTabsOnClick="true"
properties="cas.monitor.endpoints.jdbc" %}
{%- endcapture -%}
<div style="display:none" id="jdbcauthpropReference">
    {{ jdbcauthprops | markdownify }}
</div>

{%- capture ldapauthprops -%}{% include_cached casproperties.html
disableSearch="true"
id=actuatorEndpointRandomNumber
disablePagination="true"
disableNotes="true"
forcePropertyTabsOnClick="true"
properties="cas.monitor.endpoints.ldap" %}
{%- endcapture -%}
<div style="display:none" id="ldapauthpropReference">
    {{ ldapauthprops | markdownify }}
</div>

{%- capture jaasauthprops -%}{% include_cached casproperties.html
disableSearch="true"
id=actuatorEndpointRandomNumber
disablePagination="true"
disableNotes="true"
forcePropertyTabsOnClick="true"
properties="cas.monitor.endpoints.jaas" %}
{%- endcapture -%}
<div style="display:none" id="jaasauthpropReference">
    {{ jaasauthprops | markdownify }}
</div>


{%- capture jsonauthprops -%}{% include_cached casproperties.html
disableSearch="true"
id=actuatorEndpointRandomNumber
disablePagination="true"
disableNotes="true"
forcePropertyTabsOnClick="true"
properties="cas.monitor.endpoints.json" %}
{%- endcapture -%}
<div style="display:none" id="jsonauthpropReference">
    {{ jsonauthprops | markdownify }}
</div>

{%- capture casendpointsconfigprops -%}{% include_cached casproperties.html
disableSearch="true"
id=actuatorEndpointRandomNumber
disablePagination="true"
disableNotes="true"
forcePropertyTabsOnClick="true"
properties="cas.monitor.endpoints.form-login-enabled,cas.monitor.endpoints.endpoint" %}
{%- endcapture -%}

{%- if include.casModule.size > 0 -%}
{%- assign casmodule = include.casModule -%}
{%- capture casModuleReference -%}{% include_cached casmodule.html group="org.apereo.cas" module=casmodule id=actuatorEndpointRandomNumber %}{%- endcapture -%}
{%- endif %}

<div class="accordion" id="{{ actuatorEndpointRandomNumber }}">
    {%- assign showClass = "show" -%}

    {%- for endpoint in endpoints -%}

    {%- for configblock in site.data[siteDataVersion].actuators[endpoint] -%}
    {%- assign config = configblock[1] | sort: "method" -%}

    {%- for cfg in config -%}

    {%- assign key = cfg.path
    | append: cfg.method
    | remove: "["
    | remove: "]"
    | remove: '"'
    | remove: '/'
    | remove: '$'
    | remove: rbrace
    | remove: lbrace -%}

    <span class="accordion-header" id="heading{{key}}">
        <button {% if showClass contains "show" %} class="accordion-button" {% else %}
            class="accordion-button collapsed" {% endif %} type="button" data-bs-toggle="collapse"
            data-bs-target="#collapse{{key}}" {% if showClass contains "show" %}aria-expanded="true" {% endif %}
            style="height: 40px; padding-top: 30px; border-radius: 6px;" aria-controls="collapse{{key}}">
            <table style="border: none;">
                <tr>
                    <td style="width: 6%; border-bottom:none;">

                        {%- if cfg.method == "DELETE" -%}
                        <span class="badge bg-danger">
                            {%- elsif cfg.method == "GET" -%}
                            <span class="badge bg-primary">
                                {%- elsif cfg.method == "POST" -%}
                                <span class="badge bg-success">
                                    {%- else -%}
                                    <span class="badge bg-secondary">
                                        {%- endif -%}

                                        {%- if cfg.casEndpoint == true -%}
                                        <i class="fas fa-copyright"></i>
                                        {%- else -%}
                                        <i class="fab fa-codepen"></i>
                                        {%- endif -%}
                                        &nbsp;
                                        {{ cfg.method }}
                                    </span>
                    </td>
                    <td style="border-bottom:none;"><span><code>/cas/actuator/{{ cfg.path }}</code>
                            <sup>
                                {%- if cfg.casEndpoint == true -%}
                                <img class="undecorated img-fluid" width="42px" src="../../images/cas-sm.png"
                                     data-bs-toggle="tooltip" data-bs-placment="top" data-bs-html="true"
                                     title="This endpoint is owned, provided and controlled by CAS."
                                     class="fas fa-copyright">
                                {%- else -%}
                                <i data-bs-toggle="tooltip" data-bs-placment="top" data-bs-html="true"
                                   title="This endpoint is provided by a third-party framework to CAS."
                                   class="fa fa-code"></i>
                                {%- endif -%}
                            </sup>
                        </span></td>
                </tr>
            </table>
        </button>
    </span>

    <div id="collapse{{key}}" class="accordion-collapse collapse {{ showClass }}" aria-labelledby="heading{{key}}"
         data-bs-parent="#{{ actuatorEndpointRandomNumber }}">
        <div class="accordion-body card card-body">
            {% assign io="" %}

            {%- if cfg.returnType.size > 0 -%}
            {%- assign io = "Return Type: <code>" | append: cfg.returnType | append: "</code><p>" -%}
            {%- endif -%}

            {%- if cfg.consumes.size > 0 -%}
            {%- assign io = io | append: "Content Type: <code>" | append: cfg.consumes | append: "</code><p>" -%}
            {%- endif -%}

            {%- if cfg.produces.size > 0 -%}
            {%- assign io = io | append: "Accept: <code>" | append: cfg.produces | append: "</code><p>" -%}
            {%- endif -%}

            {%- if cfg.deprecated == true -%}
            {%- assign io = io | append: "Deprecated<p>" -%}
            {%- endif -%}

            {%- assign io = io | append: "Signature: <code>" | append: cfg.signature | markdownify | append: "</code><p>" -%}

            {%- assign io = io | append: "Owner: <code>" | append: cfg.owner | append: "</code><p>" -%}

            <p class="small text-left">
                <a tabindex="0" class="btn btn-sm btn-info" role="button" data-bs-toggle="popover" data-bs-trigger="hover"
                   title="Input & Output" data-bs-html="true" data-bs-content='{{io}}'>
                    <i aria-hidden="true" class="fa fa-question"></i>
                </a>
                <a tabindex="0" title="Endpoint Details" class="btn btn-sm btn-success" role="button"
                   data-bs-toggle="modal" data-bs-target="#{{key}}ModalConfig">
                    <i aria-hidden="true" class="fa fa-book-open"></i>
                </a>
                &nbsp;
                {%- if cfg.summary.size > 0 -%}
                {{cfg.summary}}
                {%- else -%}
                {%- unless cfg.casEndpoint == true -%}
                There is no documentation available for this endpoint. The functionality presented here is provided to
                CAS via a third-party library or framework, which provides no documentation as part of endpoint definition's
                metadata.
                {% endunless -%}
                {%- endif -%}
            </p>

            <p>


            <div class="modal fade" id="{{key}}ModalConfig" tabindex="-1" aria-hidden="true">
                <div class="modal-dialog modal-dialog-centered modal-xl modal-dialog-scrollable">
                    <div class="modal-content">
                        <div class="modal-header">
                            <h4 class="modal-title">Endpoint Details: <code>{{ cfg.path }}</code></h4>
                            <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                        </div>
                        <div class="modal-body">

                            <ul class="nav nav-tabs">
                                <li class="nav-item">
                                    <a class="nav-link active" data-bs-toggle='tab'
                                       href="#endpointintro{{ key }}">Overview</a>
                                </li>


                                <li class="nav-item">
                                    <a class="nav-link" data-bs-toggle='tab' href="#casendppointprops{{ key }}">Configuration</a>
                                </li>

                                <li class="nav-item">
                                    <a class="nav-link" data-bs-toggle='tab'
                                       href="#thirdpartyendpointprops{{ key }}">Third Party</a>
                                </li>
                                {%- if cfg.name == "health" -%}
                                <li class="nav-item">
                                    <a class="nav-link" data-bs-toggle='tab'
                                       href="#healthendpointinfo{{ key }}">Health</a>
                                </li>
                                {%- endif -%}
                                <li class="nav-item">
                                    <a class="nav-link" data-bs-toggle='tab'
                                       href="#endpointsecurity{{ key }}">Security</a>
                                </li>
                                <li class="nav-item">
                                    <a class="nav-link" data-bs-toggle='tab'
                                       href="#endpointtroubleshooting{{ key }}">Troubleshooting</a>
                                </li>
                            </ul>

                            <div class='tab-content'>
                                <div class="tab-pane fade active show" id="endpointintro{{key}}">
                                    <br />
                                    {%- assign allQueryParams="" -%}
                                    {%- if cfg.parameters.size > 0 -%}
                                    <h5>Endpoint Parameters</h5>
                                    <ul>
                                        {% for param in cfg.parameters -%}
                                            {%- assign paramName = param.name | replace: "()", "" -%}
                                            <li>
                                                {%- if param.required == true -%}
                                                {%- assign paramTitle = "Parameter is required." -%}
                                                {%- else -%}
                                                {%- assign paramTitle = "Parameter is optional." -%}
                                                {%- endif -%}

                                                {%- if param.selector == true -%}
                                                    {%- assign paramTitle = paramTitle | append: " This parameter can be specified as a path variable." -%}
                                                {%- else -%}
                                                    {%- assign paramTitle = paramTitle | append: " This parameter can be specified as a query parameter." -%}
                                                    {%- assign allQueryParams = allQueryParams | append: paramName | append: "=...&" -%}
                                                {%- endif -%}
                                                <i class="fas fa-info-circle" data-bs-toggle="tooltip"
                                                   data-bs-placment="top" data-bs-html="true"
                                                   title="{{ paramTitle }}"></i>
                                                <code>{{ paramName }} ({{ param.type }})</code>
                                                {%- if param.description.size > 0 -%}: <span>{{ param.description }}</span>{%- endif -%}
                                            </li>
                                        {%- endfor -%}
                                    </ul>
                                    {%- endif -%}


                                    <div>
                                        <p>Once the endpoint is available, here is an example of how you could use it with <code>curl</code>: </p>
{% capture curlrequest %}
```bash
curl -k -u "username:password" \
-X {{ cfg.method }} \
-X "Content-Type: {{ cfg.consumes[0] | default: 'application/json' }}" \
-X "Accept: {{ cfg.produces[0] | default: 'application/json' }}" \
"https://sso.example.org/cas/actuator/{{ cfg.path }}?{{ allQueryParams }}"
```{% endcapture %}
{{ curlrequest | markdownify }}
                                    </div>

                                    <p>CAS, being a Spring-Boot application at heart, includes a number of endpoints to help you monitor and manage the server when it’s pushed to production. You can choose to manage and monitor the deployment using HTTP endpoints, referred to as actuators.</p>
                                    <p>
                                        In essence, actuator endpoints bring production-ready features to CAS. Monitoring a running CAS instance, gathering metrics, understanding traffic or the state of our database becomes trivial with such endpoints. The main benefit of these endpoints is that we can get production grade tools without having to actually implement these features ourselves. Actuators are mainly used to expose operational information about the running application – <code>health</code>, <code>metrics</code>, etc. These are HTTP endpoints or JMX beans to enable us to interact with it.
                                    </p>

                                    <p>
                                        Actuator endpoints are presented by CAS in two categories:
                                    <ul>
                                        <li>Those that are owned and defined by the CAS project.</li>
                                        <li>Those that are owned and defined by third-party projects, frameworks and libraries such as Spring Boot.</li>
                                    </ul>
                                    </p>

                                    {%- if cfg.name == "status" -%}
                                    <div class="alert alert-warning">:warning: <strong>Obtaining Health Info</strong><p>Note
                                        that <code>/status</code> endpoint is kept mostly
                                        as a legacy endpoint. If you wish to obtain health status of each monitor
                                        in detail, we recommend the <code>/actuator/health</code> endpoint instead.</p></div>
                                    {%- endif -%}

                                    <div class="alert alert-info">:information_source: <strong>Exposed Endpoints</strong><p>
                                        Note that by default the only endpoints exposed over the web
                                        are <code>info</code>, <code>status</code>, <code>health</code> and <code>configurationMetadata</code>.
                                        Other endpoints need to be explicitly <strong>enabled and then
                                        exposed over the web</strong> in CAS settings in order to allow access.
                                    </p></div>

                                    {%- if cfg.name == "metrics" -%}
                                    <p>
                                        Navigating to this endpoint displays a list of available meter names. You can drill down to view information about a
                                        particular meter by providing its name as a selector, e.g. <code>/metrics/jvm.memory.max</code>. The name you use here should match the name used in the code, not the name after it has been naming-convention normalized for a monitoring system it is shipped to.

                                        You can also add any number of <code>tag=KEY:VALUE</code> query parameters to the end of the URL to dimensionally drill
                                        down on a meter, e.g. <code>/metrics/jvm.memory.max?tag=area:nonheap</code>`

                                        The reported measurements are the sum of the statistics of all meters
                                        matching the meter name and any tags that have been applied.
                                        So in the example above, the returned "Value" statistic is the sum of the maximum memory footprints of "Code Cache",
                                        "Compressed Class Space", and "Metaspace" areas of the heap. If you just wanted to see the maximum size for the "Metaspace",
                                        you could add an additional <code>tag=id:Metaspace</code>, i.e. <code>/metrics/jvm.memory.max?tag=area:nonheap&tag=id:Metaspace</code>.
                                    </p>
                                    {%- endif -%}

                                </div>


                                <div class='tab-pane fade' id='casendppointprops{{ key }}'>
                                    <br />

                                    {%- if include.casModule.size > 0 -%}
                                    <p>This endpoint, <code>{{cfg.path}}</code> can be turned
                                        on by including the following dependency in the WAR overlay:</p>

                                    <div id="casmoduleplaceholder{{ key }}">
                                        {{ casModuleReference | markdownify }}
                                    </div>
                                    {%- endif -%}


                                    <p>To enable and expose an actuator endpoint:</p>
{% capture epc %}

```properties
management.endpoint.{{ cfg.name }}.access=UNRESTRICTED
management.endpoints.web.exposure.include={{ cfg.name }}

# Choose the proper security access level...
# cas.monitor.endpoints.endpoint.{{ cfg.name }}.access=PERMIT
```{% endcapture %}
                                    <div>
{{ epc | markdownify }}
                                    </div>

                                    <div id="casEndpointConfigPropsDiv">
                                        {{ casendpointsconfigprops | replace: "[key]", cfg.name | markdownify }}

                                    </div>

                                    <p>
                                        Endpoints may be mapped to custom arbitrary endpoints. For example,
                                        to remap the <code>health</code> endpoint to <code>healthcheck</code>,
                                        specify the following settings:

{% capture health %}
```properties
management.endpoints.web.path-mapping.health=healthcheck
```{% endcapture %}
                                        <span>
{{ health | markdownify }}
</span>
                                    </p>

                                </div>
                                <div class="tab-pane fade" id="thirdpartyendpointprops{{ key }}">
                                    {{ endpointprops | markdownify }}
                                </div>

                                {%- if cfg.name == "health" -%}

                                <br/>

                                {%- capture healthendpointinfo -%}{% include_cached {{ version }}/health-actuator-configuration.md healthIndicators=include.healthIndicators %}
                                {% endcapture -%}

                                <div class="tab-pane fade" id="healthendpointinfo{{ key }}">
                                    <div>
                                        {{ healthendpointinfo | markdownify }}
                                    </div>
                                </div>
                                {%- endif -%}

                                <div class='tab-pane fade' id='endpointsecurity{{ key }}'>
                                    <br/>
                                    <div id="endpointsecurityInner{{ key }}">

                                        <script>
                                            function collapseSecurityPanels{{ key }}(el) {
                                                $('#collapseSecurityDiv{{ key }} div.collapse').removeClass('show');
                                                document.getElementById(`${el}{{ key }}`)
                                                    .addEventListener('shown.bs.collapse', () => {
                                                        let elementId = `.modal-body #${el}{{ key }} .nav-item a.nav-link:first`;
                                                        $(elementId).addClass("active")
                                                        $(elementId).click();
                                                    });
                                            }
                                        </script>

                                        <button class="btn btn-primary btn-sm" type="button" data-bs-toggle="collapse"
                                                data-bs-target="#collapseSecurityBasicAuth{{ key}}"
                                                onclick="collapseSecurityPanels{{ key }}('collapseSecurityBasicAuth');"
                                                aria-expanded="false" aria-controls="collapseSecurityBasicAuth{{ key }}">
                                            Basic Authentication
                                        </button>
                                        <button class="btn btn-primary btn-sm" type="button" data-bs-toggle="collapse"
                                                data-bs-target="#collapseSecurityJaas{{ key}}"
                                                onclick="collapseSecurityPanels{{ key }}('collapseSecurityJaas');"
                                                aria-expanded="false" aria-controls="collapseSecurityJaas{{ key }}">
                                            JAAS Authentication
                                        </button>
                                        <button class="btn btn-primary btn-sm" type="button" data-bs-toggle="collapse"
                                                data-bs-target="#collapseSecurityLdap{{ key}}"
                                                onclick="collapseSecurityPanels{{ key }}('collapseSecurityLdap');"
                                                aria-expanded="false" aria-controls="collapseSecurityLdap{{ key }}">
                                            LDAP Authentication
                                        </button>
                                        <button class="btn btn-primary btn-sm" type="button" data-bs-toggle="collapse"
                                                data-bs-target="#collapseSecurityJdbc{{ key}}"
                                                onclick="collapseSecurityPanels{{ key }}('collapseSecurityJdbc');"
                                                aria-expanded="false" aria-controls="collapseSecurityJdbc{{ key }}">
                                            JDBC Authentication
                                        </button>
                                        <button class="btn btn-primary btn-sm" type="button" data-bs-toggle="collapse"
                                                data-bs-target="#collapseSecurityJson{{ key}}"
                                                onclick="collapseSecurityPanels{{ key }}('collapseSecurityJson');"
                                                aria-expanded="false" aria-controls="collapseSecurityJson{{ key }}">
                                            JSON Authentication
                                        </button>
                                        <br />
                                    </div>
                                    <br/>

                                    <div id="collapseSecurityDiv{{ key }}">
                                        <div class="collapse" id="collapseSecurityBasicAuth{{ key }}">
                                            <div class="card card-body">
                                                {{ basicauthprops || markdownify }}

                                                <p>For basic authentication, the default username is <code>casuser</code>. The password may be automatically generated at startup and displayed in CAS logs if it is left undefined in CAS settings. Additional sources may also be defined that would authenticate the request via JAAS, LDAP, JDBC, etc. </p>
                                            </div>
                                        </div>

                                        <div class="collapse" id="collapseSecurityJdbc{{ key }}">
                                            <div class="card card-body" id="placeholderSecurityJdbc{{ key }}">
                                            </div>
                                        </div>

                                        <div class="collapse" id="collapseSecurityLdap{{ key }}">
                                            <div class="card card-body" id="placeholderSecurityLdap{{ key }}">
                                            </div>
                                        </div>

                                        <div class="collapse" id="collapseSecurityJaas{{ key }}">
                                            <div class="card card-body" id="placeholderSecurityJaas{{ key }}">
                                            </div>
                                        </div>
                                        <div class="collapse" id="collapseSecurityJson{{ key }}">

                                            <p>
                                                This option allows you to define a static list of users, passwords along with their role in a JSON file.
                                                The JSON file should be formatted as follows:

{% capture jsonauthfile %}
```json
[
    {
        "username": "casuser",
        "password": "{sha512}<hashed-password>",
        "authorities": [ "ROLE_ADMIN" ]
    }
]
```{% endcapture %}
<span>{{ jsonauthfile | markdownify }}</span>

                                                <p>Supported password encoding schemes are:
                                                    <code>{sha512}</code>, <code>{sha256}</code>, <code>{bcrypt}</code>,
                                                    <code>{noop}</code>, <code>{pbkdf2}</code>, <code>{scrypt}</code>,
                                                    <code>{argon2}</code>.
                                                </p>
                                            </p>

                                            <div class="card card-body" id="placeholderSecurityJson{{ key }}">
                                            </div>
                                        </div>
                                    </div>


                                    <p>
                                        Once endpoints are enabled and exposed, the security of all provided endpoints
                                        is handled
                                        by the <a href="https://spring.io/projects/spring-security">Spring Security</a>
                                        project.
                                        Protection and access to each endpoint
                                        is controlled via CAS settings individually such that you may
                                        decide a specific security level and method of authentication for each endpoint
                                        independently.

                                    <ul>
                                        <li>If CAS is configured to <strong>NOT</strong> enforce endpoint security
                                            rules, then
                                            all endpoints are considered sensitive and require authentication, typically
                                            handled
                                            via basic authentication with master credentials defined in CAS settings.
                                        </li>

                                        <li>If CAS is configured to enforce endpoint security rules, then each
                                            endpoint may be tagged with a specific security rule allowing access via
                                            authorized IP addresses,
                                            basic credentials, roles and attributes, etc. </li>
                                    </ul>

                                    <div class="alert alert-info">:information_source: <strong>Defaults</strong><p>
                                        There is a special endpoint named <code>defaults</code> which serves as a shortcut that
                                        controls the security of all endpoints, if left undefined in CAS settings.
                                    </p></div>

                                    </p>
                                </div>

                                <div class="tab-pane fade" id="endpointtroubleshooting{{ key }}">
                                    <br/>
                                    <p>To enable additional logging, configure the log4j configuration file to add the
                                        following levels:</p>
                                    {{ troubleshooting | markdownify }}
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>

            <script>
                document.getElementById('{{key}}ModalConfig').addEventListener('shown.bs.modal', event => {
                    let content = $("#jdbcauthpropReference").html();
                    $("#placeholderSecurityJdbc{{ key }}").html(content);

                    content = $("#ldapauthpropReference").html();
                    $("#placeholderSecurityLdap{{ key }}").html(content);

                    content = $("#jaasauthpropReference").html();
                    $("#placeholderSecurityJaas{{ key }}").html(content);

                    content = $("#jsonauthpropReference").html();
                    $("#placeholderSecurityJson{{ key }}").html(content);

                    let elementId = "#casEndpointConfigPropsDiv .nav-item a.nav-link:first";
                    console.log(`Selecting configuration tab via ${elementId}`);
                    $(elementId).addClass("active");
                    $(elementId).click();
                })
            </script>
            </p>
        </div>
    </div>

    {%- assign showClass = "" -%}
    {%- endfor -%}
    {%- endfor -%}
    {%- endfor -%}
</div>

<br />
